﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;

// This was/is FLog.
// If you want a complete logging 'solution' with the kitchen sink and more, find that .NET port of log4j. (log4net?)

namespace Clandestine.Base
{
    public enum MessagePriority
    {
        Info,
        Warn,
        Misc
    }

    public static class Log
    {
        /// <summary>
        /// Do the lock (Log.ConsoleLockBlob) { // your uninterrupted console access here }, yeahhh!
        /// This is also what every logging func in this class does before writing its message.
        /// So, as long as YOU have the lock, no logging messages get written! (Unless you call a log func from inside your lock.)
        /// </summary>
        public static object ConsoleLockBlob = new object();

        // Are we on Windows? (Used for switching winColorMap, linColorMap.)
        private static bool windows;
		
		public static bool hacks = false;

        static Log()
        {
            // Figure out which OS we're on!
            PlatformID plat = System.Environment.OSVersion.Platform;
            windows = (plat == PlatformID.Win32NT || plat == PlatformID.Win32S || plat == PlatformID.Win32Windows);

            // Especially on Windows, by default the console is tiny.  Happily, we can force it to be larger!
            if (Console.WindowWidth <= 80 && windows)
                Console.BufferWidth = Console.WindowWidth = 110;
        }

        // Chooses foreground console colours for each message priority. :)
        // Note one set of colours for Windows (black background console), one for non-Windows (white).
        static Dictionary<MessagePriority, ConsoleColor> winColorMap = new Dictionary<MessagePriority, ConsoleColor> {
            { MessagePriority.Info, ConsoleColor.Gray },
            { MessagePriority.Warn, ConsoleColor.Yellow },
		{ MessagePriority.Misc, ConsoleColor.White } };
        static Dictionary<MessagePriority, ConsoleColor> linColorMap = new Dictionary<MessagePriority, ConsoleColor> {
            { MessagePriority.Info, ConsoleColor.Black },
            { MessagePriority.Warn, ConsoleColor.DarkYellow },
		{ MessagePriority.Misc, ConsoleColor.Black } };

        // What a log line is prefixed with, depending on the set message priority.
        static Dictionary<MessagePriority, string> indicatorMap = new Dictionary<MessagePriority, string> {
            { MessagePriority.Info,  "(i) " },
            { MessagePriority.Warn, " !  " } };

        private static string getPrefix()
        {
            StackTrace st = new StackTrace(true);
            StackFrame frame = st.GetFrame(hacks ? 5 : 3); // i.e. func before i()/w()/f() in stack

            DateTime now = DateTime.Now;

            // HH:MM:ss.mmm Filename.cs:ThunderFunc(68) 
            return ensureZeroes(now.Hour.ToString(), 2) + ":" + ensureZeroes(now.Minute.ToString(), 2) + ":"
                + ensureZeroes(now.Second.ToString(), 2) + "." + ensureZeroes(now.Millisecond.ToString(), 3)
                + " " + Path.GetFileName(frame.GetFileName()) + ":" + frame.GetMethod().Name
                + "(" + frame.GetFileLineNumber().ToString() + ") ";
        }

        private static string ensureZeroes(string s, int digits)
        {
            while (s.Length < digits)
                s = "0" + s;
            return s;
        }

        private static void writeLine(MessagePriority mp, string message)
        {
            lock (ConsoleLockBlob)
            {
                //Console.BackgroundColor = (windows ? ConsoleColor.Black : ConsoleColor.White);

                // Set new foreground colour based on MessagePriority & write the damn line!
                //Console.ForegroundColor = (windows ? winColorMap : linColorMap)[mp];
				if (mp == MessagePriority.Warn)
				{
					Console.BackgroundColor = ConsoleColor.Black;
					Console.ForegroundColor = ConsoleColor.Yellow;
				}
				
                Console.WriteLine(indicatorMap[mp] + getPrefix());

				// Restore original colours.
                Console.ResetColor();
				
                // Second line - actual message details.
                //Console.ForegroundColor = (windows ? winColorMap : linColorMap)[MessagePriority.Misc];
                Console.WriteLine("\t" + message);

                
            }
        }

        /// <summary>
        /// Clears the Console and sets the background colour to white, and the foreground colour to black.
        /// </summary>
        public static void Clear()
        {
            // Yep, call this func if you want our colours!
            Console.BackgroundColor = (windows ? ConsoleColor.Black : ConsoleColor.White);
            Console.ForegroundColor = (windows ? ConsoleColor.Gray : ConsoleColor.Black);
            Console.Clear();
        }

        /// <summary>
        /// Puts 'info'-priority message to the console.
        /// </summary>
        /// <param name="infoMessage">'Info'-priority message to write to the console</param>
        public static void i(string infoMessage)
        {
            writeLine(MessagePriority.Info, infoMessage);
        }

        public static void i(string format, params object[] args)
        {
            writeLine(MessagePriority.Info, string.Format(format, args));
        }

        /// <summary>
        /// Puts 'warning'-priority message to the console.
        /// </summary>
        /// <param name="warnMessage">'Warning'-priority message to write to the console</param>
        public static void w(string warnMessage)
        {
            writeLine(MessagePriority.Warn, warnMessage);
        }

        public static void w(string format, params object[] args)
        {
            writeLine(MessagePriority.Warn, string.Format(format, args));
        }
    }
}
